/**
 * @license
 * Copyright (C) 2020 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/**
 * This is a base template for TypeScript plugins.
 *
 * When extending this template you have to:
 * - Set the __plugindir variable.
 */

const path = require('path');
const {defineConfig, globalIgnores} = require('eslint/config');
const js = require('@eslint/js');
const {FlatCompat} = require('@eslint/eslintrc');

const compat = new FlatCompat({
  baseDirectory: __dirname,
  recommendedConfig: js.configs.recommended,
  allConfig: js.configs.all,
});

module.exports = defineConfig([
  ...compat.config({
    extends: ['eslint:recommended', 'google'],
    parserOptions: {
      ecmaVersion: 9,
      sourceType: 'module',
    },
    env: {
      browser: true,
      es6: true,
    },
    rules: {
      // https://eslint.org/docs/rules/no-confusing-arrow
      'no-confusing-arrow': 'error',
      // https://eslint.org/docs/rules/newline-per-chained-call
      'newline-per-chained-call': ['error', {ignoreChainWithDepth: 2}],
      // https://eslint.org/docs/rules/arrow-body-style
      'arrow-body-style': ['error', 'as-needed',
        {requireReturnForObjectLiteral: true}],
      // https://eslint.org/docs/rules/arrow-parens
      'arrow-parens': ['error', 'as-needed'],
      // https://eslint.org/docs/rules/block-spacing
      'block-spacing': ['error', 'always'],
      // https://eslint.org/docs/rules/brace-style
      'brace-style': ['error', '1tbs', {allowSingleLine: true}],
      // https://eslint.org/docs/rules/camelcase
      'camelcase': 'off',
      // https://eslint.org/docs/rules/comma-dangle
      'comma-dangle': ['error', {
        arrays: 'always-multiline',
        objects: 'always-multiline',
        imports: 'always-multiline',
        exports: 'always-multiline',
        functions: 'never',
      }],
      // https://eslint.org/docs/rules/eol-last
      'eol-last': 'off',
      'guard-for-in': 'error',
      // https://eslint.org/docs/rules/indent
      'indent': ['error', 2, {
        MemberExpression: 2,
        FunctionDeclaration: {body: 1, parameters: 2},
        FunctionExpression: {body: 1, parameters: 2},
        CallExpression: {arguments: 2},
        ArrayExpression: 1,
        ObjectExpression: 1,
        SwitchCase: 1,
      }],
      // https://eslint.org/docs/rules/keyword-spacing
      'keyword-spacing': ['error', {after: true, before: true}],
      // https://eslint.org/docs/rules/lines-between-class-members
      'lines-between-class-members': ['error', 'always'],
      // https://eslint.org/docs/rules/max-len
      'max-len': [
        'error',
        80,
        2,
        {
          ignoreComments: true,
          ignorePattern: '^import .*;$',
        },
      ],
      // https://eslint.org/docs/rules/new-cap
      'new-cap': ['error', {
        capIsNewExceptions: ['Polymer'],
        capIsNewExceptionPattern: '^.*Mixin$',
      }],
      // https://eslint.org/docs/rules/no-console
      'no-console': [
        'error',
        {allow: ['warn', 'error', 'info', 'assert', 'group', 'groupEnd']},
      ],
      // https://eslint.org/docs/rules/no-multiple-empty-lines
      'no-multiple-empty-lines': ['error', {max: 1}],
      // https://eslint.org/docs/rules/no-prototype-builtins
      'no-prototype-builtins': 'off',
      // https://eslint.org/docs/rules/no-redeclare
      'no-redeclare': 'off',
      // https://eslint.org/docs/rules/no-trailing-spaces
      'no-trailing-spaces': 'error',
      // https://eslint.org/docs/rules/no-irregular-whitespace
      'no-irregular-whitespace': 'error',
      // https://eslint.org/docs/rules/array-callback-return
      'array-callback-return': ['error', {allowImplicit: true}],
      // https://eslint.org/docs/rules/no-restricted-syntax
      'no-restricted-syntax': [
        'error',
        {
          selector: 'ExpressionStatement > CallExpression > ' +
              'MemberExpression[object.name=\'test\'][property.name=\'only\']',
          message: 'Remove test.only.',
        },
        {
          selector: 'ExpressionStatement > CallExpression > ' +
              'MemberExpression[object.name=\'suite\'][property.name=\'only\']',
          message: 'Remove suite.only.',
        },
      ],
      // no-undef disables global variable.
      // "globals" declares allowed global variables.
      // https://eslint.org/docs/rules/no-undef
      'no-undef': ['error'],
      // https://eslint.org/docs/rules/no-useless-escape
      'no-useless-escape': 'off',
      // https://eslint.org/docs/rules/no-var
      'no-var': 'error',
      // https://eslint.org/docs/rules/operator-linebreak
      'operator-linebreak': 'off',
      // https://eslint.org/docs/rules/object-shorthand
      'object-shorthand': ['error', 'always'],
      // https://eslint.org/docs/rules/padding-line-between-statements
      'padding-line-between-statements': [
        'error',
        {
          blankLine: 'always',
          prev: 'class',
          next: '*',
        },
        {
          blankLine: 'always',
          prev: '*',
          next: 'class',
        },
      ],
      // https://eslint.org/docs/rules/prefer-arrow-callback
      'prefer-arrow-callback': 'error',
      // https://eslint.org/docs/rules/prefer-const
      'prefer-const': 'error',
      // https://eslint.org/docs/rules/prefer-promise-reject-errors
      'prefer-promise-reject-errors': 'error',
      // https://eslint.org/docs/rules/prefer-spread
      'prefer-spread': 'error',
      // https://eslint.org/docs/rules/prefer-object-spread
      'prefer-object-spread': 'error',
      // https://eslint.org/docs/rules/quote-props
      'quote-props': ['error', 'consistent-as-needed'],
      // https://eslint.org/docs/rules/semi
      'semi': ['error', 'always'],
      // https://eslint.org/docs/rules/template-curly-spacing
      'template-curly-spacing': 'error',

      // https://eslint.org/docs/rules/require-jsdoc
      'require-jsdoc': 0,
      // https://eslint.org/docs/rules/valid-jsdoc
      'valid-jsdoc': 0,
      // https://github.com/gajus/eslint-plugin-jsdoc#eslint-plugin-jsdoc-rules-check-alignment
      'jsdoc/check-alignment': 2,
      // https://github.com/gajus/eslint-plugin-jsdoc#eslint-plugin-jsdoc-rules-check-examples
      'jsdoc/check-examples': 0,
      // https://github.com/gajus/eslint-plugin-jsdoc#eslint-plugin-jsdoc-rules-check-indentation
      'jsdoc/check-indentation': 0,
      // https://github.com/gajus/eslint-plugin-jsdoc#eslint-plugin-jsdoc-rules-check-param-names
      'jsdoc/check-param-names': 0,
      // https://github.com/gajus/eslint-plugin-jsdoc#eslint-plugin-jsdoc-rules-check-syntax
      'jsdoc/check-syntax': 0,
      // https://github.com/gajus/eslint-plugin-jsdoc#eslint-plugin-jsdoc-rules-check-tag-names
      'jsdoc/check-tag-names': 0,
      // https://github.com/gajus/eslint-plugin-jsdoc#eslint-plugin-jsdoc-rules-check-types
      'jsdoc/check-types': 0,
      // https://github.com/gajus/eslint-plugin-jsdoc#eslint-plugin-jsdoc-rules-implements-on-classes
      'jsdoc/implements-on-classes': 2,
      // https://github.com/gajus/eslint-plugin-jsdoc#eslint-plugin-jsdoc-rules-match-description
      'jsdoc/match-description': 0,
      // https://github.com/gajus/eslint-plugin-jsdoc#eslint-plugin-jsdoc-rules-no-types
      'jsdoc/no-types': 0,
      // https://github.com/gajus/eslint-plugin-jsdoc#eslint-plugin-jsdoc-rules-no-undefined-types
      'jsdoc/no-undefined-types': 0,
      // https://github.com/gajus/eslint-plugin-jsdoc#eslint-plugin-jsdoc-rules-require-description
      'jsdoc/require-description': 0,
      // https://github.com/gajus/eslint-plugin-jsdoc#eslint-plugin-jsdoc-rules-require-description-complete-sentence
      'jsdoc/require-description-complete-sentence': 0,
      // https://github.com/gajus/eslint-plugin-jsdoc#eslint-plugin-jsdoc-rules-require-example
      'jsdoc/require-example': 0,
      // https://github.com/gajus/eslint-plugin-jsdoc#eslint-plugin-jsdoc-rules-require-hyphen-before-param-description
      'jsdoc/require-hyphen-before-param-description': 0,
      // https://github.com/gajus/eslint-plugin-jsdoc#eslint-plugin-jsdoc-rules-require-jsdoc
      'jsdoc/require-jsdoc': 0,
      // https://github.com/gajus/eslint-plugin-jsdoc#eslint-plugin-jsdoc-rules-require-param
      'jsdoc/require-param': 0,
      // https://github.com/gajus/eslint-plugin-jsdoc#eslint-plugin-jsdoc-rules-require-param-description
      'jsdoc/require-param-description': 0,
      // https://github.com/gajus/eslint-plugin-jsdoc#eslint-plugin-jsdoc-rules-require-param-name
      'jsdoc/require-param-name': 2,
      // https://github.com/gajus/eslint-plugin-jsdoc#eslint-plugin-jsdoc-rules-require-returns
      'jsdoc/require-returns': 0,
      // https://github.com/gajus/eslint-plugin-jsdoc#eslint-plugin-jsdoc-rules-require-returns-check
      'jsdoc/require-returns-check': 0,
      // https://github.com/gajus/eslint-plugin-jsdoc#eslint-plugin-jsdoc-rules-require-returns-description
      'jsdoc/require-returns-description': 0,
      // https://github.com/gajus/eslint-plugin-jsdoc#eslint-plugin-jsdoc-rules-valid-types
      'jsdoc/valid-types': 2,
      // https://github.com/gajus/eslint-plugin-jsdoc#eslint-plugin-jsdoc-rules-require-file-overview
      'jsdoc/require-file-overview': ['error', {
        tags: {
          license: {
            mustExist: true,
            preventDuplicates: true,
          },
        },
      }],
      // https://github.com/benmosher/eslint-plugin-import/blob/master/docs/rules/no-self-import.md
      'import/no-self-import': 2,
      // The no-cycle rule is slow, because it doesn't cache dependencies.
      // Disable it.
      // https://github.com/benmosher/eslint-plugin-import/blob/master/docs/rules/no-cycle.md
      'import/no-cycle': 0,
      // https://github.com/benmosher/eslint-plugin-import/blob/master/docs/rules/no-useless-path-segments.md
      'import/no-useless-path-segments': 2,
      // https://github.com/benmosher/eslint-plugin-import/blob/master/docs/rules/no-unused-modules.md
      'import/no-unused-modules': 2,
      // https://github.com/benmosher/eslint-plugin-import/blob/master/docs/rules/no-default-export.md
      'import/no-default-export': 2,
      // Prevents certain identifiers being used.
      // Prefer flush() over flushAsynchronousOperations().
      'id-blacklist': ['error', 'flushAsynchronousOperations'],
    },

    overrides: [
      {
        files: ['eslint.config.js'],
        env: {
          browser: false,
          es6: true,
          node: true,
        },
      },
      {
        // .js-only rules
        files: ['**/*.js'],
        rules: {
          // https://github.com/gajus/eslint-plugin-jsdoc#eslint-plugin-jsdoc-rules-require-param-type
          'jsdoc/require-param-type': 2,
          // https://github.com/gajus/eslint-plugin-jsdoc#eslint-plugin-jsdoc-rules-require-returns-type
          'jsdoc/require-returns-type': 2,
          // The rule is required for .js files only, because typescript compiler
          // always checks import.
          'import/no-unresolved': 2,
          'import/named': 2,
        },
      },
      {
        files: ['**/*.ts'],
        extends: [require.resolve('gts/.eslintrc.json')],
        rules: {
          'no-restricted-imports': ['error', {
            name: '@polymer/decorators/lib/decorators',
            message: 'Use @polymer/decorators instead',
          }],
          '@typescript-eslint/no-explicit-any': 'error',
          // See https://github.com/GoogleChromeLabs/shadow-selection-polyfill/issues/9
          '@typescript-eslint/ban-ts-comment': 'off',
          // The following rules is required to match internal google rules
          '@typescript-eslint/restrict-plus-operands': 'error',
          '@typescript-eslint/no-unused-vars': [
            'error',
            {argsIgnorePattern: '^_'},
          ],
          // https://github.com/mysticatea/eslint-plugin-node/blob/master/docs/rules/no-unsupported-features/node-builtins.md
          'node/no-unsupported-features/node-builtins': 'off',
          // Disable no-invalid-this for ts files, because it incorrectly reports
          // errors in some cases (see https://github.com/typescript-eslint/typescript-eslint/issues/491)
          // At the same time, we are using typescript in a strict mode and
          // it catches almost all errors related to invalid usage of this.
          'no-invalid-this': 'off',

          'node/no-extraneous-import': 'off',

          // Typescript already checks for undef
          'no-undef': 'off',

          'jsdoc/no-types': 2,
        },
        parserOptions: {
          // The __plugindir variable has to be defined by the plugin config.
          project: path.resolve(__dirname, __plugindir, 'tsconfig.json'),
        },
      },
    ],
    plugins: [
      'html',
      'jsdoc',
      'import',
      'prettier',
    ],
    settings: {
      'html/report-bad-indent': 'error',
      'import/resolver': {
        node: {},
      },
    },
  }),
]);

